﻿using System;
using System.ComponentModel;
using System.Threading.Tasks;

using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

using Uhimania.Libraries.Test;

using Uhimania.Libraries.Windows.Interactivity;

namespace Windows.InteractivityTest
{
    [TestClass]
    public class EventTriggerTest
    {
        #region EventName

        #region 正常ケース
        [TestMethod]
        public async Task EventName_正常ケース()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var trigger = new EventTrigger();
                trigger.EventName = "foo";
                trigger.EventName.Is("foo");
            });
        }
        #endregion

        #endregion

        #region SourceObject

        #region 正常ケース
        [TestMethod]
        public async Task SourceObject_正常ケース()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var obj = new object();
                var trigger = new EventTrigger();
                trigger.SourceObject = obj;
                trigger.SourceObject.Is(obj);
            });
        }
        #endregion

        #region Attach
        [TestMethod]
        public async Task SourceObject_Attach()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new FrameworkElementMock();
                var trigger = new EventTrigger();

                Interaction.GetTriggers(mock).Add(trigger);
                (trigger.AsDynamic().SourceObjectCore as object).Is(mock);

                Interaction.GetTriggers(mock).Remove(trigger);
                (trigger.AsDynamic().SourceObjectCore as object).IsNull();
            });
        }
        #endregion

        #endregion

        #region AttachEvent / DetachEvent

        #region 正常ケース
        [TestMethod]
        public async Task Event_正常ケース()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new Mock();
                var action = new ActionMock();
                var trigger = new EventTrigger();
                trigger.Actions.Add(action);
                trigger.SourceObject = mock;
                trigger.EventName = "Event";

                action.called.Is(false);

                mock.RaiseEvent();

                action.called.Is(true);

                trigger.SourceObject = null;
                action.called = false;
                mock.RaiseEvent();

                action.called.Is(false);
            });
        }
        #endregion

        #region Generic
        [TestMethod]
        public async Task Event_Generic()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new Mock();
                var action = new ActionMock();
                var trigger = new EventTrigger();
                trigger.Actions.Add(action);
                trigger.SourceObject = mock;
                trigger.EventName = "EventT";

                action.called.Is(false);

                mock.RaiseEventT();

                action.called.Is(true);

                trigger.EventName = "Event";
                action.called = false;
                mock.RaiseEventT();

                action.called.Is(false);
            });
        }
        #endregion

        #region 派生イベント型
        [TestMethod]
        public async Task Event_派生イベント型()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new Mock();
                var action = new ActionMock();
                var trigger = new EventTrigger();
                trigger.Actions.Add(action);
                trigger.SourceObject = mock;
                trigger.EventName = "PropertyChanged";

                action.called.Is(false);

                mock.RaisePropertyChanged();

                action.called.Is(true);

                trigger.SourceObject = new Mock();
                action.called = false;
                mock.RaisePropertyChanged();

                action.called.Is(false);
            });
        }
        #endregion

        #region RoutedEvent
        [TestMethod]
        public async Task Event_RoutedEvent()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new RoutedMock();
                var action = new ActionMock();
                var trigger = new EventTrigger();
                trigger.Actions.Add(action);
                trigger.SourceObject = mock;
                trigger.EventName = "Event";

                action.called.Is(false);

                mock.RaiseEvent();

                action.called.Is(true);

                trigger.SourceObject = null;
                action.called = false;
                mock.RaiseEvent();

                action.called.Is(false);
            });
        }
        #endregion

        #region イベントが存在しない
        [TestMethod]
        public async Task Event_イベントが存在しない()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new Mock();
                var trigger = new EventTrigger();
                trigger.SourceObject = mock;
                AssertExtension.IsThrown<ArgumentException>(() => trigger.EventName = "test");
            });
        }
        #endregion

        #endregion

        #region Mock

        private class Mock
        {
            public event EventHandler Event;
            public void RaiseEvent()
            {
                if (this.Event != null)
                    this.Event(this, new EventArgs());
            }

            public event EventHandler<PropertyChangedEventArgs> EventT;
            public void RaiseEventT()
            {
                if (this.EventT != null)
                    this.EventT(this, new PropertyChangedEventArgs(""));
            }

            public event PropertyChangedEventHandler PropertyChanged;
            public void RaisePropertyChanged()
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(""));
            }
        }

        private class RoutedMock
        {
            public event Windows.UI.Xaml.RoutedEventHandler Event;
            public void RaiseEvent()
            {
                if (this.Event != null)
                    this.Event(this, new Windows.UI.Xaml.RoutedEventArgs());
            }
        }

        private class ActionMock : TriggerAction
        {
            public bool called = false;
            protected override void Invoke(object parameter)
            {
                this.called = true;
            }
        }

        private class FrameworkElementMock : Windows.UI.Xaml.FrameworkElement
        {
        }

        #endregion
    }
}
